# IMPORT GUI FILE
from ui_super import *
from Custom_Widgets.Widgets import *
import sys
# import os

# from PySide2.QtWidgets import QListWidgetItem, QFileDialog
from PySide2.QtGui import *
from PySide2.QtWidgets import *
from PySide2.QtCore import *

import serial
# import pandas as pd
# import numpy as np
import time
import math
from struct import *
from serial.tools.list_ports import comports

# 数据处理
from DataPros import *
from collections import defaultdict


class SleepControl:

    def __init__(self, workingInterval, func_GetCurSecond=None):

        self.workingInterval = workingInterval
        if func_GetCurSecond is None:
            func_GetCurSecond = lambda: time.time()
        self.func_GetCurSecond = func_GetCurSecond

        self.Reset()

    def Reset(self):
        self.gotoSleepTime = 0
        self.delayTime = 0
        self.sec0 = self.func_GetCurSecond()

    def AboutToSleep(self):
        self.gotoSleepTime = self.func_GetCurSecond() - self.sec0
        # print(self.gotoSleepTime)

    def GetNextSleepDur(self):
        # 计算自上次休眠时到现在为止已经过了多久
        deltaTime = self.func_GetCurSecond() - self.sec0 - self.gotoSleepTime
        self.delayTime += deltaTime - self.workingInterval

        ret = 0
        if self.delayTime >= self.workingInterval:
            ret = 0
        elif self.delayTime > 0:
            ret = self.workingInterval - self.delayTime
        else:
            ret = self.workingInterval - self.delayTime
        return ret

    def SetWorkingInterval(self, New_workingInterval):
        self.workingInterval = New_workingInterval


class MainWindow(QMainWindow):
    sigCmd = Signal(str)
    sigPosition = Signal(int)
    sigDat = Signal(PlayerData)
    sigPort = Signal(str)

    def __init__(self):
        QMainWindow.__init__(self)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        loadJsonStyle(self, self.ui)

        # EXPAND CENTER MENU WIDGET SIZE
        self.ui.btnInfo.clicked.connect(lambda: self.ui.centerMenuContainer.expandMenu())
        self.ui.btnMode.clicked.connect(lambda: self.ui.centerMenuContainer.expandMenu())
        self.ui.btnSettings.clicked.connect(lambda: self.ui.centerMenuContainer.expandMenu())

        # CLOSE CENTER MENU WIDGET SIZE
        self.ui.closeCenterMenuBtn.clicked.connect(lambda: self.ui.centerMenuContainer.collapseMenu())

        # 串口选择控件
        self.ui.btnSettings.setIcon(QIcon('icons8-settings-64.png'))
        for port in comports():
            self.ui.comboBox.addItem(port.name)

        self.ui.comboBox.currentIndexChanged.connect(self.change_port)

        # 关联按钮和函数
        self.ui.btnPlay.setEnabled(False)
        self.ui.btnAdd.clicked.connect(self.open_file)
        self.ui.btnchooseColumn.clicked.connect(self.save_columns)
        self.ui.btnPlay.clicked.connect(self.play_chosen)
        self.ui.slider.sliderMoved.connect(self.change_position)

        # 单击文件更新播放状态，双击显示文件的可输出列
        self.ui.playlist.clicked.connect(self.set_state)
        self.ui.playlist.doubleClicked.connect(self.choose_columns)

        # 切换上下文件的按钮
        self.ui.btnPrevious.clicked.connect(self.skip2previous)
        self.ui.btnNext.clicked.connect(self.skip2next)

        # 切换播放模式的按钮
        self.ui.sequentialPlay.clicked.connect(self.modeSequential)
        self.ui.singleCycle.clicked.connect(self.modeSingleCycle)
        self.ui.listCycle.clicked.connect(self.modeListCycle)
        self.ui.randomPlay.clicked.connect(self.modeRandom)

        self.state = "Pause"
        self.playing = ""
        self.index = 0
        self.mode = "sequential"
        self.fileCount = 0
        self.columns_dict = defaultdict(list)  # {'filename': [('column1', 0)]}

        # 创建播放器线程
        self.thread = Player()

        # 关联与播放器线程通信用的信号与槽
        self.sigDat.connect(self.thread.DataSlot)
        self.sigCmd.connect(self.thread.cmd_slot)
        self.sigPosition.connect(self.thread.position_slot)
        self.sigPort.connect(self.thread.port_slot)
        self.thread.position_changed.connect(self.set_position)
        self.thread.finished.connect(self.playWithMode)
        self.thread.start()

    def change_port(self):
        serName = self.ui.comboBox.currentText()
        self.sigPort.emit(serName)
        print("changePort")

    def open_file(self):
        file_name = QFileDialog()
        file_name.setFileMode(QFileDialog.ExistingFiles)
        names = file_name.getOpenFileNames(None, "Open files", os.getenv("HOME"))
        self.myfile = names[0]
        self.ui.playlist.addItems(self.myfile)
        self.fileCount = self.ui.playlist.count()
        print(self.fileCount)

    # 数据处理函数：双击一个文件时将文件中可输出列返回到界面供用户选择
    def choose_columns(self):

        self.ui.columnsList.clear()

        filepath = self.ui.playlist.currentItem().text()
        if filepath in self.columns_dict and self.columns_dict[filepath] != []:
            for column in self.columns_dict[filepath]:
                item = QListWidgetItem(column[0])
                item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
                if column[1] == 0:
                    item.setCheckState(QtCore.Qt.Unchecked)
                else:
                    item.setCheckState(QtCore.Qt.Checked)
                self.ui.columnsList.addItem(item)

        else:
            columnsInfile = selectChn(filepath).get("ChnName")
            for column in columnsInfile:
                item = QListWidgetItem(column)
                item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
                item.setCheckState(QtCore.Qt.Unchecked)
                self.ui.columnsList.addItem(item)

    def save_columns(self):
        filepath = self.ui.playlist.currentItem().text()
        self.columns_dict[filepath] = []
        for index in range(self.ui.columnsList.count()):
            if self.ui.columnsList.item(index).checkState() == Qt.Checked:
                self.columns_dict[filepath].append((self.ui.columnsList.item(index).text(), 1))
            else:
                self.columns_dict[filepath].append((self.ui.columnsList.item(index).text(), 0))

    # def getData(self, columns):
    #     filepath = self.ui.playlist.currentItem().text()
    #     df_all = pd.read_csv(filepath)
    #     df = df_all[columns[0:]]
    #     mat = np.array(df)
    #
    #     dct = {
    #         'File length ': len(mat),
    #         'Sample rate ': 50,
    #         'number of current channels': len(columns)
    #     }
    #
    #     dat = PlayerData(mat, dct)
    #
    #     return dat

    def play_chosen(self):

        if self.state == "Pause":
            self.state = "Play"
            self.ui.btnPlay.setIcon(QIcon('icons8-pause-24.png'))
            filepath = self.ui.playlist.currentItem().text()
            # 播放一个新文件
            if filepath != self.playing:

                self.playing = filepath
                self.index = self.ui.playlist.currentRow().__index__()

                # 得到用户选择的可播放列
                playColumns = list()
                # column_i = 0
                for item in self.columns_dict[filepath]:
                    if item[1] == 1:
                        playColumns.append(item[0])
                        # playColumns.append(column_i)

                print(playColumns)
                # data = self.getData(playColumns)
                data = newChn(filepath, playColumns)
                self.ui.slider.setRange(0, data.ctrlInfo['File length '] - 1)
                self.sigCmd.emit('stop')
                self.sigDat.emit(data)
                self.sigCmd.emit('play')

            # 继续播放暂停状态的文件
            else:
                self.sigCmd.emit('play')

        else:
            self.state = "Pause"
            self.ui.btnPlay.setIcon(QIcon('icons8-play-30.png'))
            self.sigCmd.emit('pause')

# ------------------------------------------------------------------
    def set_position(self, val):
        self.ui.slider.setValue(val)

    def change_position(self, position):
        self.sigPosition.emit(position)

    def skip2previous(self):
        self.state = "Pause"
        self.ui.playlist.setCurrentRow((self.index - 1) % self.fileCount)
        self.play_chosen()

    def skip2next(self):
        self.state = "Pause"
        self.ui.playlist.setCurrentRow((self.index + 1) % self.fileCount)
        self.sigCmd.emit('stop')
        self.play_chosen()

    def set_state(self):
        self.ui.btnPlay.setEnabled(True)
        self.state = "Pause"
        self.ui.btnPlay.setIcon(QIcon('icons8-play-30.png'))

    def modeSequential(self):
        self.mode = "sequential"
        self.ui.btnMode.setIcon(QIcon('icons8-list-24.png'))

    def modeSingleCycle(self):
        self.mode = "singleCycle"
        self.ui.btnMode.setIcon(QIcon('icons8-repeat-one-30.png'))

    def modeListCycle(self):
        self.mode = "listCycle"
        self.ui.btnMode.setIcon(QIcon('icons8-repeat-30.png'))

    def modeRandom(self):
        self.mode = "random"
        self.ui.btnMode.setIcon(QIcon('icons8-shuffle-30.png'))
        self.array = np.arange(self.fileCount)
        print(self.array)
        np.random.shuffle(self.array)
        print(self.array)
        self.radom_i = np.where(self.array == self.index)[0][0]
        print(self.radom_i)

    def playWithMode(self):
        self.state = "Pause"
        if self.mode == "sequential":
            if self.index == self.fileCount - 1:
                print("all done")
                self.sigCmd.emit('pause')
                self.ui.btnPlay.setIcon(QIcon('icons8-play-30.png'))
                return
            else:
                self.ui.playlist.setCurrentRow(self.index + 1)

        elif self.mode == "listCycle":
            self.ui.playlist.setCurrentRow((self.index + 1) % self.fileCount)

        elif self.mode == "random":
            self.radom_i = self.radom_i + 1
            self.ui.playlist.setCurrentRow(self.array[self.radom_i % self.fileCount])

        self.play_chosen()


class Player(QThread):
    position_changed = Signal(int)
    finished = Signal()

    def __init__(self):
        super(Player, self).__init__()
        self.isPaused = True
        self.isToCancel = False
        self.row = 0

        self.Blob = PlayerData(np.ndarray(0), {})

        self.ser = None

        self.sample_rate = 25
        self.workingInterval = 0.05
        self.countOfF = ''

    def cmd_slot(self, cmd):
        if cmd == 'play':
            self.isPaused = False
        elif cmd == 'pause':
            self.isPaused = True
        elif cmd == 'stop':
            self.isToCancel = True

    def position_slot(self, position_i):
        self.row = position_i

    def DataSlot(self, dat: PlayerData):
        self.Blob = dat
        self.sample_rate = self.Blob.ctrlInfo['Sample rate ']
        self.workingInterval = 0.05
        self.countOfF = ''.join('f' for i in range(dat.ctrlInfo['number of current channels'])) + 'BBBB'

    def port_slot(self, port):
        self.ser = serial.Serial(port)

    def run(self):

        sleepCtrl = SleepControl(self.workingInterval)

        timeToSleep = sleepCtrl.GetNextSleepDur()
        sleepCtrl.AboutToSleep()
        time.sleep(timeToSleep)

        while True:

            if self.Blob.dataBlob.size > 0:

                samplePerInterval = math.ceil(self.workingInterval * self.sample_rate)
                print(self.sample_rate)
                print(samplePerInterval)
                print(self.Blob.ctrlInfo['File length '])

                self.workingInterval = samplePerInterval / self.sample_rate
                sleepCtrl.SetWorkingInterval(self.workingInterval)

                while self.row <= self.Blob.ctrlInfo['File length ']:
                    timeToSleep = sleepCtrl.GetNextSleepDur()
                    sleepCtrl.AboutToSleep()

                    if timeToSleep > 0.001:
                        time.sleep(timeToSleep)

                    if self.row == self.Blob.ctrlInfo['File length ']:
                        self.row = 0
                        self.finished.emit()
                        break

                    if self.isToCancel:
                        self.isToCancel = False
                        self.row = 0
                        break

                    if self.isPaused:
                        continue

                    # 判断是否出界
                    for i in range(samplePerInterval):
                        data = pack(self.countOfF, *self.Blob.dataBlob[self.row], 0x00, 0x00, 0x80, 0x7F)
                        self.ser.write(data)
                        self.position_changed.emit(self.row)
                        self.row = self.row + 1
                        if self.row == self.Blob.ctrlInfo['File length ']:
                            break
                        if self.isToCancel:
                            self.row = 0
                            self.position_changed.emit(self.row)
                            break

            else:
                timeToSleep = sleepCtrl.GetNextSleepDur()
                sleepCtrl.AboutToSleep()

                if timeToSleep > 0.001:
                    time.sleep(timeToSleep)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

